package model;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import model.iview.ITile;
import util.Resources;
import exceptions.EmptyBagException;

/**
 * Cette classe représente le sac des tuiles dans lequel les joueurs piochent
 * leurs lettres. Il est chargé à partir d'un fichier texte.
 * 
 * @author Lucile Gramusset et Guillaume Poussel
 * 
 */
public class Bag {

    /**
     * Contenu du sac
     */
    private List<Tile> content;

    /**
     * Lit le fichier texte et retourne une Map représentant le contenu du sac
     */
    public static Map<ITile, Integer> getDistribution() {
        HashMap<ITile, Integer> lettres = new HashMap<ITile, Integer>();
        BufferedReader bagText;
        String line = "";
        // Ouvrir le fichier du sac
        try {
            bagText = new BufferedReader(new InputStreamReader(Resources.getBagInputStream()));
            if (bagText == null) {
                throw new FileNotFoundException(Resources.getString("Bag.FileNotFound"));
            }

            // Remplit le sac

            while ((line = bagText.readLine()) != null) {
                if (line != null) {
                    StringTokenizer st = new StringTokenizer(line);

                    while (st.hasMoreTokens()) {
                        String strLetter = st.nextToken().toUpperCase();
                        if (st.hasMoreTokens()) {
                            int count = 0;
                            int score = 0;
                            if (st.hasMoreTokens()) {
                                count = Integer.parseInt(st.nextToken());
                            }
                            if (st.hasMoreTokens()) {
                                score = Integer.parseInt(st.nextToken());
                            }
                            while (count-- > 0) {
                                Tile tile = new Tile(Letter.valueOf(strLetter),
                                        score);
                                if (lettres.containsKey(tile)) {
                                    lettres.put(tile, lettres.get(tile) + 1);
                                } else {
                                    lettres.put(tile, 1);
                                }
                            }
                        }
                    }
                }
            }
            while (line != null);

            bagText.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lettres;
    }

    /**
     * Lit le fichier texte et retourne une ArrayList de tuiles
     */
    private static List<Tile> getContenu() {
        List<Tile> contenu = new ArrayList<Tile>();
        BufferedReader bagText;
        String line = "";
        // Ouvrir le fichier du sac
        try {
            bagText = new BufferedReader(new InputStreamReader(Resources.getBagInputStream()));
            if (bagText == null) {
                throw new FileNotFoundException(Resources.getString("Bag.FileNotFound"));
            }

            // Remplit le sac

            while ((line = bagText.readLine()) != null) {
                if (line != null) {
                    StringTokenizer st = new StringTokenizer(line);

                    while (st.hasMoreTokens()) {
                        String strLetter = st.nextToken().toUpperCase();
                        if (st.hasMoreTokens()) {
                            int count = 0;
                            int score = 0;
                            if (st.hasMoreTokens()) {
                                count = Integer.parseInt(st.nextToken());
                            }
                            if (st.hasMoreTokens()) {
                                score = Integer.parseInt(st.nextToken());
                            }
                            while (count-- > 0) {
                                Tile tile = new Tile(Letter.valueOf(strLetter),
                                        score);
                                contenu.add(tile);
                            }
                        }
                    }
                }
            }
            while (line != null);

            bagText.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return contenu;
    }

    /**
     * Construit le sac à partir de la distribution donnée dans le fichier
     * texte.
     */
    public Bag() {
        this.content = Bag.getContenu();
    }

    /**
     * Détermine si le sac est vide ou non
     * 
     * @return <code>true</code> si le sac est vide, <code>false</code> sinon.
     */
    public boolean isEmpty() {
        return content.isEmpty();
    }

    /**
     * Donne la taille du sac en nombre de tuiles restantes
     * 
     * @return Le nombre de tuiles restantes
     */
    public int size() {
        return content.size();
    }

    /**
     * Retourne une tuile au hasard dans le sac. Cette méthode mélange le sac à
     * chaque fois que l'on pioche une tuile.
     * 
     * @return Une tuile piochée au hasard dans le sac
     * @throws EmptyBagException
     *             Si le sac est vide, une exception est levée
     */
    public Tile take() throws EmptyBagException {
        if (isEmpty())
            throw new EmptyBagException(Resources.getString("Bag.Empty"));
        Collections.shuffle(content);
        return content.remove(content.size() - 1);
    }

    /**
     * Repose une tuile dans le sac et mélange le sac.
     * 
     * @param tile
     *            La tuile à reposer dans le sac
     */
    public void put(Tile tile) {
        content.add(tile);
        Collections.shuffle(content);
    }

    public String toString() {
        return content.toString();
    }
}
